<template>
    <div class="codeEditBox" v-loading="loading">
		<div class="nav">
			
			<div class="hidden-lg-and-up" v-if="model.length > 0">
				<el-dropdown @command="change" trigger="click">
					<el-button type="text" style="color: #fff;">
						{{model[index].type}}
					</el-button>
					<el-dropdown-menu slot="dropdown">
						<el-dropdown-item v-for="(item, index) in model"
						:command="index"
						:key="index">{{ item.type }}</el-dropdown-item>
					</el-dropdown-menu>
				</el-dropdown>
			</div>
			<div v-if="!paper">
				<el-rate
					v-model="topic.level"
					disabled
					>
				</el-rate>
			</div>
			<div v-if="paper" style="font-size: 1vw;">
				{{ format }}
			</div>
			<div class="hidden-lg-and-up" @click="submit('test')">
				<i class="el-icon-caret-right"></i>
			</div>
			<div class="hidden-lg-and-up" @click="submit('submit')">
				<i class="el-icon-check"></i>
			</div>
		</div>
        <div class="box" v-if="model.length > 0">
			<div class="left">
				<editor v-model="code" @init="editorInit" 
				@input='codeChange' :lang="model[index].type"
				:options="editorOptions"
				theme="ambiance"
				></editor>
				<div class="hidden-md-and-down list" v-if="paper">
					<div 
					:style="{backgroundColor : 
						listIndex == i ? '#E6A23C' : 
						item.answerItem ? '#67C23A' : '#777'}"
					v-for="(item,i) in list" :key="i">{{ i + 1 }}</div>
					<div v-if="list.length > 10"><i class="el-icon-more"></i></div>
				</div>
			</div>
			<div class="right hidden-md-and-down">
				<div class="nav">
					语言
					<el-select v-model="index"
					@change="change"
					placeholder="请选择">
						<el-option
						v-for="(item,i) in model"
						:key="item.type"
						:label="item.type"
						:value="i">
						</el-option>
					</el-select>
				</div>
				<div class="content">
					<h1>{{ topic.title }}</h1>
					<div v-html="topic.content" v-highlight></div>
				</div>
				<div class="btn">
					<div class="test" @click="submit('test')">测试</div>
					<div class="submit" @click="submit('submit')">提交</div>
				</div>
			</div>
		</div>
		<div class="hidden-lg-and-up showInfo">
			<div v-if="paper" @click="drawer = true"><i class="el-icon-more"></i></div>
			<div @click="drawer = true"><i class="el-icon-document"></i></div>
		</div>
		
		<codeKey :keys="codeKeys" class="hidden-lg-and-up"/>

		<topicPreview :topic="topic" :drawer="drawer" @handleClose="drawer = false"/>

		<el-dialog
			title="Error"
			:visible.sync="dialogVisible"
			width="95%">
			<div class="errorMsg" v-html="toHtml(errorMsg)"></div>
			<span slot="footer" class="dialog-footer">
				<el-button type="primary" @click="dialogVisible = false">确 定</el-button>
			</span>
		</el-dialog>
    </div>
</template>

<script>
	import Editor from 'vue2-ace-editor'
	import { getTopicDetail } from '@/api/topic'
	import {  } from '@/api/answer'
	import { testAnswerItem, saveAnswerItem } from '@/api/answerItem'
	import { editAnswer } from '@/api/answer'
    import { stringToResult, resultToString } from '@/assets/js/topicResult'
	import { mapState, mapMutations } from 'vuex'
	import topicPreview from '@/components/topic/topicPreview.vue'
	import codeKey from '@/components/base/codeKey.vue'
	import { toHtml } from '@/utils/textToHtml' 
	export default {
		name: 'CodeEditor',
		components: {
			Editor,
			topicPreview,
			codeKey
		},
		data() {
			return {
                // 双向绑定的编辑器内容值属性
				index : 0,
				drawer : false,
				dialogVisible : false,
				errorMsg : '',
				code: ``,
				model : [],
				editorOptions: {
					// 设置代码编辑器的样式
					enableBasicAutocompletion: true, //启用基本自动完成
					enableSnippets: true, // 启用代码段
					enableLiveAutocompletion: true, //启用实时自动完成
					tabSize: 4, //标签大小
					fontSize: 17, //设置字号
					showPrintMargin: false //去除编辑器里的竖线
				},
				topicResult : [],
				topic : {},
				list : [],
				listIndex : 0,
				titmrID : undefined,//
				titmr : new Date().getTime(),//
				loading : false,
			}
		},
		computed : {
			...mapState(['paper', 'codeKeys']),
            format(){
				if(this.paper.answer){
                    let t = this.paper.answer.createTime + this.paper.paper.time - this.titmr
                    return `${parseInt(t / 60000)}分${parseInt(t % 60000 / 1000)}秒`
                }
                return parseInt(this.paper.paper.time / 60000) + '分钟'
            },
		},
		created(){
			if(this.$route.query.id){
				this.getData()
				this.closePaper()
			}else if (this.paper) {
				this.list = this.paper.list
				this.findListIndex()
				this.getTopicByPaper()
				this.titmrID = setInterval(() => {
                    this.titmr = new Date().getTime()
                }, 1000)
			}else{
				this.$router.replace('/student/homePaper')
			}
		},
		methods: {
			toHtml,
			...mapMutations(['closePaper']),
			getData(){
				this.loading = true
				getTopicDetail(this.$route.query.id).then(res => {
					this.loading = false
					if(res.code == 200){
						this.topicResult = stringToResult(res.data.result)
						this.topic = res.data.topic
						this.analysis()
					}
				})
			},

			// 查找做题的的位置
			findListIndex(){
				this.listIndex = 0
				this.list.forEach(n => {
					if (!n.answerItem) {
						return
					}
					this.listIndex++
				})
			},

			// 获取从试卷中的题目
			getTopicByPaper(){
				let data = this.list[this.listIndex]
				this.topic = data.topic
				this.topicResult = stringToResult(data.result)
				this.analysis()
				if (data.answerItem) {
					this.type = data.answerItem.code
					this.index = data.answerItem.type == 'java' ? 1 : 0
				}
			},

			// 解析参数
			analysis(){
				this.model = []
				let jsParams = ''
				let javaParams = ''

				let obj = this.topicResult[0]

				if (!obj) {
					this.$message.error('该题目没有实例')
					this.$router.push('/student/home')
					return
				}

				for (let index = 0; index < obj.params.length; index++) {
					const element = obj.params[index];
					let s = String.fromCharCode(97 + index)
					jsParams += s
					javaParams += element.dataType + ' ' + s
					if (index + 1 != obj.params.length) {
						jsParams += ', '
						javaParams += ', '
					}
				}

				this.model.push({
					type : 'javascript',
					code : `return function (${jsParams}){}`
				})
				this.model.push({
					type : 'java',
					code : `public class Test{\n\tpublic ${obj.result.dataType} main(${javaParams}){}\n}`
				})

				this.code = this.model[0].code
			},
            // 编辑内容改变时触发
			codeChange(val) {
				// val 
				// console.log(val)
			},
			//初始化代码编辑器
			editorInit() {
				require('brace/theme/ambiance')
				require('brace/ext/language_tools') //language extension prerequsite...
				require('brace/mode/yaml')
				require('brace/mode/json')
				require('brace/mode/less')
				require('brace/mode/lua')
				require('brace/mode/java')
				require('brace/mode/javascript')
				require('brace/snippets/javascript')
				require('brace/snippets/lua')
				require('brace/snippets/java')
				require('brace/snippets/json')
			},
			// 提交按钮的回调
			submit(type){
				if (this.index == 0) {
					try{
						let a = new Function(this.code)
						let result = this.take(a())
						if (type == 'test') {
							this.$message({
								type : result ? 'success' : 'error',
								message : result ? '测试通过' : '测试未通过'
							})
						}else{
							this.submitAftr(result ? 1 : 0)
						}
					}catch(e){
						// this.$message(e.toString())
						this.errorMsg = e.toString()
						this.dialogVisible = true
					}
				}else{
					if (type == 'test') {
						testAnswerItem({
							topicId : this.topic.id,
							answerId : this.paper ? this.paper.answer.id : 0,
							code : this.code,
							type : this.model[this.index].type,
						}).then(res => {
							if (res.code == 200) {
								this.$message({
									type : res.data.type,
									message : res.data.msg
								})
							}else{
								this.errorMsg = res.msg
								this.dialogVisible = true
							}
						})
					}else{
						this.submitAftr()
					}
				}
			},

			// 提交
			submitAftr(result){

				let data = {
					topicId : this.topic.id,
					answerId : this.paper ? this.paper.answer.id : 0,
					code : this.code,
					type : this.model[this.index].type,
					result : result
				}

				this.$confirm('确认提交吗？', '提示')
				.then(() => {
					this.loading = true
					saveAnswerItem(data).then(res => {
						this.loading = false
						if(res.code == 200){
							this.$message.success('提交成功')

							if(!this.paper){
								this.$router.back()
								return
							}

							this.list[this.listIndex].answerItem = data
							this.findListIndex()
							if(this.list.length > this.listIndex){
								this.getTopicByPaper()
							}else{
								this.$confirm('试卷已完成', '提示').then(() => {
									editAnswer({
										id : this.paper.answer.id,
										paperId : this.paper.paper.id,
										status : 1,
									})
									this.$router.push('/student/homePaper')
								})
							}
						}else{
							this.errorMsg = res.msg
							this.dialogVisible = true
						}
					})
				})
				.catch(() => {});
			},

			/**
			 * 解析数据
			 * @param {*} element 后端的数据例如：{data : '1', dataType : 'int'}
			 * @return {*} 数据
			 */
			convertData(element){
				if (element.dataType.indexOf('[]') != -1) {
					let d = element.data.split(',')
					for (let index = 0; index < d.length; index++) {
						d[index] = parseData(element.dataType, d[index])
					}
					return d
				}

				return parseData(element.dataType, element.data)

				function parseData(dataType, data){
					if (dataType.indexOf('int') != -1) {
						return parseInt(data)
					}else if(dataType.indexOf('double') != -1){
						return parseFloat(data)
					}else if(dataType.indexOf('String') != -1){
						return data + ''
					}
				}
			},

			// 判断js代码的正确性
			take(fn){
				for (var obj in this.topicResult) {
					let e = this.topicResult[obj]
					let arr = []
					for (let index = 0; index < e.params.length; index++) {
						arr.push(this.convertData(e.params[index]))
					}
					let res = this.convertData(e.result)

					if (!eq(fn(...arr), res)) {
						return false
					}
				}

				function eq(a, b){
					if (a == b) {
						return true
					}
					if (JSON.stringify(a) == JSON.stringify(b)) {
						return true
					}
					if (a && a.sort && b.sort && a.sort().toString() == b.sort().toString()) {
						return true
					}
					if (String(a) == String(b)) {
						return
					}
					return false
				}

				return true
			},
			// 切换语言
			change(index){
				this.index = index
				this.code = this.model[this.index].code
			}
		},
        beforeDestroy(){
            if (this.titmrID) {
                clearInterval(this.titmrID)
            }
        },
	}
</script>
 
<style lang="scss" scoped>
	.codeEditBox {
		width: 100%;
		height: 100%;
		display: flex;
		flex-direction: column;
		&>.nav{
			height: 50px;
			width: 100%;
			background-color: lightseagreen;
			display: flex;
			justify-content: space-around;
			align-items: center;
			font-size: 22px;
			color: #fff;
			&>div{
				margin: 0 10px;
			}
		}
		.box{
			display: flex;
			width: 100%;
			margin: 0 auto;
			height: calc(100vh - 50px);
			.left{
				width: 100%;
				height: 100%;
				position: relative;
				.list{
					position: absolute;
					right: 10px;
					bottom: 0;
					width: 80%;
					height: 60px;
					display: flex;
					justify-content: end;
					&>div{
						color: #fff;
						width: 30px;
						height: 30px;
						line-height: 30px;
						text-align: center;
						margin: 5px;
						background-color: #777;
						cursor: pointer;
						border-radius: 5px;
					}
				}
			}
			.right{
				width: 40%;
				height: 100%;
				position: relative;
				padding: 20px;
				.nav{
					width: 100%;
					height: 50px;
				}
				.content{
					overflow-y: auto;
					height: calc(100% - 100px);
					width: 100%;
					div{
						font-size: 18px;
						line-height: 2rem;
					}
				}
				.btn{
					position: absolute;
					bottom: 0px;
					right: 0px;
					display: flex;
					justify-content: right;
					&>div{
						margin: 10px;
						height: 50px;
						width: 130px;
						line-height: 50px;
						text-align: center;
						font-weight: 900;
						color: #fff;
						cursor: pointer;
						background-color: lightseagreen;
						border-radius: 10px;
						transition: all 1s;
						&:hover{
							background-color: chocolate;
						}
					}
				}
			}
		}
		.showInfo{
			position: fixed;
			bottom: 40px;
			right: 20px;
			font-size: 19px;
			color: #fff;
			&>div{
				width: 40px;
				height: 40px;
				cursor: pointer;
				border-radius: 50%;
				display: flex;
				justify-content: center;
				align-items: center;
				background-color: lightseagreen;
				margin-top: 20px;
			}
		}
		.errorMsg{
			color: #f00;
			line-height: 2em;
		}
	}
</style>